//
//  BaseModel.m
//  MobileGuide
//
//  Created by 鞠 文杰 on 14-2-27.
//  Copyright (c) 2014年 CSICS. All rights reserved.
//

#import "DOObjects.h"
#import "BaseModelManager.h"

@interface DOObjects (){
//    NSString *url;
    NSString *_fetchURL;
    NSString *_deleteURL;
    NSString *_updateURL;
    NSString *_saveURL;
    NSString *reasonFlag;
    NSOperationQueue *queue;
}

@end

@implementation DOObjects

+ (NSArray *)jsonObjToModel:(id)jsonObject
{
    NSMutableArray *marr = [NSMutableArray array];
    //如果是数组
    if ([jsonObject isKindOfClass:[NSArray class]]) {
        NSArray *arr = (NSArray*)jsonObject;
        NSDictionary *properties = [self  propertiesWithEncodedTypes];
        NSArray *propertyNames = [properties allKeys];
        id model;
        for (NSDictionary *dic in arr) {
            model = [[self alloc] init];
            for (NSString *propertyName in propertyNames) {
                NSString *type = [properties objectForKey:propertyName];
                //如果是对象类型
                if ([type hasPrefix:@"@"]) {
                    type = [type substringWithRange:NSMakeRange(2, type.length-3)];
                    if (isNSArrayType(type))
                    {
                        if ([propertyName rangeOfString:@"_"].location>0) {
                            NSArray *parts = [propertyName componentsSeparatedByString:@"_"];
                            NSString *className = parts[0];
                            NSString *variableName = parts[1];
                            Class subClass = objc_lookUpClass([className UTF8String]);
                            [model setValue:[subClass jsonObjToModel:[dic objectForKey:variableName]] forKey:propertyName];
                        }
                    }
                    else if(isNSDictionaryType(type))
                    {
                        
                    }
                    else if (isNSSetType(type))
                    {
                        
                    }
                    else if(isNSStringType(type))
                    {
                        [model setValue:[dic objectForKey:propertyName] forKey:propertyName];
                    }
                    else if (isNSNumberType(type))
                    {
                        NSNumber *num = (NSNumber*)[dic objectForKey:propertyName];
                        [model setValue:num forKey:propertyName];
                    }else{
                        //对象类型
                        //                        type = [type substringWithRange:NSMakeRange(2, type.length-3)];
                        Class subClass = objc_lookUpClass([type UTF8String]);
                        if ([subClass isSubclassOfClass:[DOObjects class]]) {
                            NSDictionary *subDic = [dic objectForKey:propertyName];
                            NSArray *subModels = [subClass jsonObjToModel:subDic];
                            if (subModels.count>0) {
                                [model setValue:subModels[0] forKey:propertyName];
                            }
                        }
                    }
                }else{
                    if ([type isEqualToString:@"i"] || // int
                        [type isEqualToString:@"l"] || // long
                        [type isEqualToString:@"q"] || // long long
                        [type isEqualToString:@"s"] || // short
                        [type isEqualToString:@"B"] )  // bool or _Bool
                    {
                        //                    long long value = sqlite3_column_int64(statement, i);
                        NSNumber *colValue = [NSNumber numberWithLongLong:[[dic objectForKey:propertyName] longLongValue]];
                        [model setValue:colValue forKey:propertyName];
                    }
                    else if  ([type isEqualToString:@"I"] || // unsigned int
                              [type isEqualToString:@"L"] || // usigned long
                              [type isEqualToString:@"Q"] || // unsigned long long
                              [type isEqualToString:@"S"]) // unsigned short
                    {
                        //                    unsigned long long value = sqlite3_column_int64(statement, i);
                        NSNumber *colValue = [NSNumber numberWithUnsignedLongLong:[[dic objectForKey:propertyName] unsignedLongLongValue]];
                        [model setValue:colValue forKey:propertyName];
                    }
                    else if ([type isEqualToString:@"f"] || // float
                             [type isEqualToString:@"d"] )  // double
                    {
                        NSNumber *colValue = [NSNumber numberWithDouble:[[dic objectForKey:propertyName] doubleValue]];
                        [model setValue:colValue forKey:propertyName];
                    }
                }
                
            }
            [marr addObject:model];
            model = nil;
        }
    }else if([jsonObject isKindOfClass:[NSDictionary class]]){
        NSDictionary *dic = (NSDictionary*)jsonObject;
        NSDictionary *properties = [self  propertiesWithEncodedTypes];
        NSArray *propertyNames = [properties allKeys];
        id model = [[self alloc] init];
        for (NSString *propertyName in propertyNames) {
            NSString *type = [properties objectForKey:propertyName];
            //如果是对象类型
            if ([type hasPrefix:@"@"]) {
                
                type = [type substringWithRange:NSMakeRange(2, type.length-3)];
                
                if (isNSArrayType(type))
                {
                    
                }
                else if (isNSDictionaryType(type))
                {
                    
                }
                else if (isNSSetType(type))
                {
                    
                }
                else if (isNSStringType(type))
                {
                    [model setValue:[dic objectForKey:propertyName] forKey:propertyName];
                }
                else if (isNSNumberType(type))
                {
                    
                }else{
                    //对象类型
                    //                        type = [type substringWithRange:NSMakeRange(2, type.length-3)];
                    Class subClass = objc_lookUpClass([type UTF8String]);
                    if ([subClass isSubclassOfClass:[DOObjects class]]) {
                        NSDictionary *subDic = [dic objectForKey:propertyName];
                        NSArray *subModels = [subClass jsonObjToModel:subDic];
                        if (subModels.count>0) {
                            [model setValue:subModels[0] forKey:propertyName];
                        }
                    }
                    
                }
            }else{
                if ([type isEqualToString:@"i"] || // int
                    [type isEqualToString:@"l"] || // long
                    [type isEqualToString:@"q"] || // long long
                    [type isEqualToString:@"s"] || // short
                    [type isEqualToString:@"B"] )  // bool or _Bool
                {
                    //                    long long value = sqlite3_column_int64(statement, i);
                    NSNumber *colValue = [NSNumber numberWithLongLong:[[dic objectForKey:propertyName] longLongValue]];
                    [model setValue:colValue forKey:propertyName];
                }
                else if  ([type isEqualToString:@"I"] || // unsigned int
                          [type isEqualToString:@"L"] || // usigned long
                          [type isEqualToString:@"Q"] || // unsigned long long
                          [type isEqualToString:@"S"]) // unsigned short
                {
                    //                    unsigned long long value = sqlite3_column_int64(statement, i);
                    NSNumber *colValue = [NSNumber numberWithUnsignedLongLong:[[dic objectForKey:propertyName] unsignedLongLongValue]];
                    [model setValue:colValue forKey:propertyName];
                }
                else if ([type isEqualToString:@"f"] || // float
                         [type isEqualToString:@"d"] )  // double
                {
                    NSNumber *colValue = [NSNumber numberWithDouble:[[dic objectForKey:propertyName] doubleValue]];
                    [model setValue:colValue forKey:propertyName];
                }
            }
            
        }
        [marr addObject:model];
    }
    return marr;
}

+ (NSArray *)jsonObjToModel:(id)jsonObject className:(NSString*)className
{
    return [NSArray array];
}

+ (NSDictionary *)propertiesWithEncodedTypes
{
    NSDictionary  *properties = [[BaseModelManager sharedSingleton] getClassProperties:[self class]];
    if (properties!=nil) {
        return properties;
    } else {
        // Recurse up the classes, but stop at NSObject. Each class only reports its own properties, not those inherited from its superclass
        NSMutableDictionary *theProps;
        
        if ([self superclass] != [DOObjects class])
            theProps = (NSMutableDictionary *)[[self superclass] propertiesWithEncodedTypes];
        else
            theProps = [NSMutableDictionary dictionary];
        
        unsigned int outCount;
        //if not define的缩写
        //测试 TARGET_OS_COCOTRON是否被定义
        //如果没有被定义
#ifndef TARGET_OS_COCOTRON
        objc_property_t *propList = class_copyPropertyList([self class], &outCount);
#else
        //	NSArray *propList = [cls getPropertiesList];
        NSArray *propList = [NSArray array];
        outCount = [propList count];
#endif
        int i;
        
        // Loop through properties and add declarations for the create
        for (i=0; i < outCount; i++)
        {
#ifndef TARGET_OS_COCOTRON
            objc_property_t oneProp = propList[i];
            NSString *propName = [NSString stringWithUTF8String:property_getName(oneProp)];
            NSString *attrs = [NSString stringWithUTF8String: property_getAttributes(oneProp)];
            // Read only attributes are assumed to be derived or calculated
            // See http://developer.apple.com/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/chapter_8_section_3.html
            //只读属性不可修改
            //如果为可修改属性，设置property的属性类型
            if ([attrs rangeOfString:@",R,"].location == NSNotFound)
            {
                NSArray *attrParts = [attrs componentsSeparatedByString:@","];
                if (attrParts != nil)
                {
                    if ([attrParts count] > 0)
                    {
                        NSString *propType = [[attrParts objectAtIndex:0] substringFromIndex:1];
                        [theProps setObject:propType forKey:propName];
                    }
                }
            }
#else
            NSArray *oneProp = [propList objectAtIndex:i];
            NSString *propName = [oneProp objectAtIndex:0];
            NSString *attrs = [oneProp objectAtIndex:1];
            [theProps setObject:attrs forKey:propName];
#endif
        }
        
#ifndef TARGET_OS_COCOTRON
        free( propList );
#endif
        
        [[BaseModelManager sharedSingleton] registerInMemory:[self class] properties:theProps];
        return theProps;
    }
}

//- (id)init
//{
//    @throw [NSException exceptionWithName:@"错误的初始化方法" reason:@"请使用带有url的初始化方法" userInfo:@{}];
//}

- (id)initWithURL:(NSString *)theUrl
{
    self = [super init];
    if (self) {
        _fetchURL = theUrl;
        _autoBuildBody = YES;
        queue = [[NSOperationQueue alloc] init];
    }
    return self;
}

- (void)setFailureReasonFlag:(NSString *)flag
{
    reasonFlag = flag;
}

//还要考虑多个对象内容需要提交的情况
- (void)saveInBackground:(DOBooleanResultBlock)block
{
    NSString *theUrl = _fetchURL;
    theUrl = [theUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:theUrl] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:kDOParseTimeOut];
    [req setHTTPMethod:@"POST"];
    
    NSString *body ;
    if (_autoBuildBody) {
        body = [self buildHttpBody];
    }else{
        body = [self description];
    }
    [req setValue:[NSString stringWithFormat:@"%d",[body length]] forHTTPHeaderField:@"Content-Length"];
    
    [req setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]];
    
    [NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        //如果没有连接错误
        if (!connectionError) {
            NSError *err;
            id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&err];

            if (!err) {
                if ([jsonObject isKindOfClass:[NSDictionary class]]) {
                    BOOL successFlag = [[jsonObject objectForKey:@"success"] boolValue];
                    if (successFlag) {
                        block(YES,nil);
                    }else{
                        NSString *resultFlag = reasonFlag?reasonFlag:@"result";
                        NSError *error = [NSError errorWithDomain:kDOParseErrorDomain code:kDOParseCustomError userInfo:@{@"error": [jsonObject objectForKey:resultFlag]}];
                        block(NO,error);
                    }
                }
            }else{
                block(NO,err);
            }
        }else{
            block(NO,connectionError);
        }
    }];
}

- (NSString *) buildHttpBody
{
    NSMutableString *buildStr = [[NSMutableString alloc] init];
    [buildStr appendString:@""];
    
    NSDictionary *properties = [[self class] propertiesWithEncodedTypes];
    NSArray *propertyNames = [properties allKeys];
    
    //目前仅支持不带关系的数据保存
    //遍历所有字段
    for (NSString *propName in propertyNames) {
        NSString *propType = [properties objectForKey:propName];
        if ([propType hasPrefix:@"@"]) {
            //如果是对象类型,放弃其他类型
            NSString *type = [propType substringWithRange:NSMakeRange(2, propType.length-3)];
            if (isNSStringType(type)) {
                [buildStr stringByAppendingFormat:@"%@=%@&",propName,[self valueForKey:propName]];
                NSLog(@"%@",[NSString stringWithFormat:@"%@=%@&",propName,[self valueForKey:propName]]);
            }
        }else{
            //基础类型
            [buildStr stringByAppendingString:[NSString stringWithFormat:@"%@=%@",propName,[self valueForKey:propName]]];
        }
    }
    [buildStr stringByAppendingString:@"asdfasdf"];
    return [buildStr description];
}

- (DOObjects *)fetchURL:(NSString *)url
{
    _fetchURL = url;
    return self;
}

- (DOObjects *)deleteURL:(NSString *)url
{
    _deleteURL = url;
    return self;
}

- (DOObjects *)updateURL:(NSString *)url
{
    _updateURL = url;
    return self;
}

- (DOObjects *)saveURL:(NSString *)url
{
    _saveURL = url;
    return self;
}

@end
